Autoya Informationを仕上げる
概要
なかなか大変なので記事にすることでモチベを上げる。という不思議な試み。
Autoyaっていうフレームワークがあるんだけど、まあ、そこで、WebViewを使いたくないんだよ。
Autoya
https://github.com/sassembla/Autoya
で、このInformationという機能で、
WebViewなしでhtml/markdownをuGUIパーツを使って描画する
みたいなことをやっていて。
その中でそろそろリファクタリングしようなみたいな感じになってきたので、そのまとめとしてこの記事があるっていうね。
心意気
WebViewを使わずにそれっぽいビューを表示したい。
markdownとかhtmlの描画ができると嬉しい。
その際にjsは完全に無視、cssは別の方法で実装、レイアウトにはUnityのuGUIから独自タグを作り出してそれを使う、という感じに殴りつけている。
なぜWebViewを避けるのか
・イベントフックが毎回面倒い
・遅い
・たかだかお知らせとかを出すためには機能過多
・遅い
・イベント入力位置とかビューの位置情報とかをUnity側と同期するのがしんどい
・遅い
・プラットフォームを跨いだ実装が存在しない
・遅い
・各種exploitの源になることができる
・遅い
・機能の初期化や更新などがいい感じに重い
・あと遅い
などの理由があり、あと根本的に遅いため、WebViewへの依存を殺傷することを真面目に考えるに至った。
既存構造
・md/htmlをparseしてLayout(レイアウト計算)する
・Layout済みのビューをMaterialize(実体化 = uGUI化)する
という感じで、まずLayout -> Materializeという順番で動かすことだけを考えて実装していた。
まあこれがうまくいかないケースが出てきた。
Problem1:Layoutにロード後の素材の情報が必須
画面幅だけを与えた画像(width=100%、height指定なし)とかに対して、
widthを画面幅で出すことは容易なのだけれど、画像の高さが未指定なので、高さを自動的に算出することができない。
仕様的には、画像のwidthが100%であれば、heightは画像のアスペクト比に応じて決定される。
このため、画像のアスペクト比が必要になる。
で、Layout機構ではまだ画像をDLしてないので、困った、っていう。
P1解決策
Layoutを遅延させて画像高さを得るか。まあそれで損することは特にないような気がする。
・Layoutにローディング要素のローディングを盛り込む
・Materializeの代わりにFocusみたいな概念を持ち込んで、指定のポイントから画面高さ分を実体化する
というような感じでいける気がする。
座標系の変更点がLayoutだけに場が閉じていれば、再度Layoutが発生したコンポーネントから先だけを再Layoutする、っていうのも容易なのでは。
ローディングがかかるチャンスは一度のほうがいい(分割ローディングする価値は無い)、という感じなんで、まあいいか。
・Layoutが完了したらハンドラが着火される
みたいな感じになる。
Problem2:いろんなハンドラについて解決する
このへんの細かいパラメータの決定条件を書かんとな。すっげー多いんだよなこの辺。
まず列挙するか。
・イベント
画像、リンク、タッチなどが仕込める。
仕込めるが、外部からどのように触れるようにするか、っていうのはまだ考えきれていない。
ビューに対してイベントを仕込んでおく、みたいなのとは別に、このビューに対してこのイベントが起こったらこうする、というのを渡せればいいと思っている。
・階層間距離処理
要素の階層構造に対応して隙間を適当にセットできる。 で、まあ、ようは、css。
・使用リソース指定
特定のAssetのセットを対応させることができる。
画面ごとに、「このUIの時に表示させる画面はコレ」みたいなのがセットできる。
階層間距離処理とかもAssetにしてしまうと良さそうな気がするな~。
よくまあ作ったもんなんだけど、これだけ広範囲に機能が存在するとほんとに使えるのか疑問符がいっぱい出てくる。
すべてハンドラのていを保っているんで、まあ内部的な拡張は容易。外部公開も容易。
でも外部公開はあんまりしないだろうな~~カスタマイズ性をAPIで表現しすぎると設定項目多くて使いづらい。
P2解決策
イベントに対して
・画像、リンクのどちらにしても、urlを受ける。
-> 発行されるメソッドの型 = ButtonとかLinkとか をenumで持つようにして、実行されるメソッド種を一個で済むようにすんべ。
-> uGUIのイベントにしちゃうのがいいかな。インスタンスどう渡すかな~。呼び出し元が限定できればいいだけだったらuGUIのイベントの必要ないんだよな~。
複数のビューを同時に出す、とかも視野に入れときたいので、それを考えると、ビューのインスタンスを取り出す時にハンドラをセットしたり、ハンドラを後からセットしたりできるといいのか。
まあやっぱAction<EventSourceType, string>一発で済むな、イベントにする必要ないや。
使用リソース指定
・階層構造に対してAssetを割り当てられるといいのかなあ。
Prefabに階層構造値を指定できる、とか?
なんらかの形でAssetが出力できればいいのか。
-> html -> view -> htmlへと再分解できるコースが存在することに気がついた。
具体的には、uGUIでビューを作る -> そこからPrefab要素を作ると、その要素をhtmlで記述して生成、レイアウトできるようになる。
本機能は、ぶっちゃけ、HTMLでUnity GUIを表示するブラウザ機構みたいな感じになる。
これがCSSの代わりだな~~。
・uGUIでGUIを作る -> HTMLでそのGUIを配置したりパラメータ出したりできる
Prefab雛形をキャンバスに並べる -> パラメータ設定
-> ビュー名をつけて保存、ってやると、
-> 階層を見て階層情報をPrefab化
-> 要素それ自体を別Prefabとして分解保存
-> リソース名フォルダがどこかに爆誕するので、それをAssetBundleにしたりすることができる。
-> リソース名 = ビュー名なので、Load時に名前を指定することで、DLしたりResourcesフォルダから探したりできる。
Problem3:Container Prefabがウザい
現状は特に意味がなく、無くせる気がする。うん。設定しないでも行けるように変更するか。
ContainerPrefabはなくても動かせる
P3解決策
Container Prefabを読み込む実装を消す。
->できた。
リファクタリングが終わっていい感じ
Layout, Materializeが綺麗に分割された。
depthを簡単に得るために、Tagに関しては、Layout開始時にすでに値になってしまっていてもいいのかもしれない。まあ後回しで良さそう。
それか単純にstaticなdepthを得る関数を用意すれば良さそう。
今後
AssetBundleの群が複数必要。
・viewNameに対応するAssetBundle群
・html内で使用される画像とかを格納したAssetBundle群
後者はInformationの枠組みを超えるAssetBundleなので、どうしようかな、頑張ってくれ的な。
前者はサポートをしたい。
具体的には、
・AssetBundle化の機構を持たせる
・DefaultとspecificをそれぞれAssetBundleにすることができる
・それらが読み込まれる(リストみたいなものを渡しとく必要はある?
できればAssetBundles機構への依存を少なくしておきたいんで、Informationから直で使うのは避けたい。
、、、
まあ悩もう。